package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceRequest;
import com.huaweicloud.sdk.iotda.v5.model.ShowDeviceResponse;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.properties.HuaweiIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    IoTDAClient huaweiClient;
    @Autowired
    private Client client;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private HuaweiIoTConfigProperties huaweiProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Value("${zzyl.iot}")
    private String iotPlatform;

    /**
     * 同步数据
     */
    @Override
    public void syncProductList() {
        //请求参数
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(200);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        //调用第三方查询产品列表
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断，如果数据为空，则中断请求
        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }

        //获取数据，存储到redis
        List<ProductVo> productVoList = response.getBody().getData().getList().getProductInfo().stream().map(
                p -> BeanUtil.toBean(p, ProductVo.class)
        ).collect(Collectors.toList());
        //存储到redis
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList));
    }

    /**
     * 查询所有产品列表
     *
     * @return 产品列表
     */
    @Override
    public List<ProductVo> allProduct() {

        //从缓存中获取数据
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //如果为空，返回空集合
        if (StringUtils.isEmpty(jsonStr)) {
            return Collections.emptyList();
        }
        //转换数据，并返回
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    @Override
    public ResponseResult<Void> registerDevice(DeviceDto deviceDto) {
        if (deviceMapper.countByDeviceName(deviceDto.getDeviceName()) > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        BeanUtil.copyProperties(deviceDto, registerDeviceRequest);
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        RegisterDeviceResponse response = null;
        try {
            response = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        if (ObjectUtil.isEmpty(response) && !response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setIotId(response.getBody().getData().getIotId());

        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //设置产品名称
        if (queryProductResponse.getBody().success) {
            device.setProductName(queryProductResponse.getBody().getData().productName);
        }

        if (device.getLocationType().equals(0)) {
            device.setPhysicalLocationType(-1);
        }

        try {
            device.setHaveEntranceGuard(0);
            deviceMapper.insert(device);
        } catch (Exception e) {
            DeleteDeviceRequest deleteProductRequest = new DeleteDeviceRequest();
            BeanUtil.copyProperties(device, deleteProductRequest);
            deleteProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            try {
                client.deleteDevice(deleteProductRequest);
            } catch (Exception e1) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }

        return ResponseResult.success();
    }

    @Override
    public PageResponse<DeviceVo> page(DevicePageQueryDto params) {
        PageHelper.startPage(params.getPageNum(), params.getPageSize());
        Page<DeviceVo> page = deviceMapper.page(params);
        return PageResponse.of(page, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(DeviceDto deviceDto) {
        if ("h".equals(iotPlatform)) {
            return queryHuaweiDeviceDetail(deviceDto);
        }
        QueryDeviceDetailRequest detailRequest = new QueryDeviceDetailRequest();
        detailRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        detailRequest.setIotId(deviceDto.getIotId());
        detailRequest.setProductKey(deviceDto.getProductKey());

        QueryDeviceDetailResponse detailResponse = null;
        try {
            detailResponse = client.queryDeviceDetail(detailRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (detailResponse.getBody().success) {
            DeviceVo deviceVo = BeanUtil.toBean(detailResponse.getBody().getData(), DeviceVo.class);
            DeviceVo device = deviceMapper.queryDeviceByIotId(deviceDto.getIotId());
            BeanUtil.copyProperties(device, deviceVo, CopyOptions.create().setIgnoreNullValue(true));
            return deviceVo;
        }
        return null;
    }

    @Override
    public Object queryDevicePropertyStatus(DeviceDto deviceDto) {
        QueryDevicePropertyStatusRequest queryDevicePropertyStatusRequest = new QueryDevicePropertyStatusRequest();
        queryDevicePropertyStatusRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryDevicePropertyStatusRequest.setDeviceName(deviceDto.getDeviceName());
        queryDevicePropertyStatusRequest.setProductKey(deviceDto.getProductKey());

        QueryDevicePropertyStatusResponse queryDevicePropertyStatusResponse = null;
        try {
            queryDevicePropertyStatusResponse = client.queryDevicePropertyStatus(queryDevicePropertyStatusRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (queryDevicePropertyStatusResponse.getBody().success) {
            QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData data = queryDevicePropertyStatusResponse.getBody().getData();
            return data;
        }
        return null;
    }

    @Override
    public Object QueryThingModelPublished(DeviceDto deviceDto) {
        QueryThingModelPublishedRequest queryThingModelPublishedRequest = new QueryThingModelPublishedRequest();
        queryThingModelPublishedRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryThingModelPublishedRequest.setProductKey(deviceDto.getProductKey());
        QueryThingModelPublishedResponse queryThingModelPublishedResponse = null;
        try {
            queryThingModelPublishedResponse = client.queryThingModelPublished(queryThingModelPublishedRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (queryThingModelPublishedResponse.getBody().success) {
            QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData data = queryThingModelPublishedResponse.getBody().getData();
            return data;
        }
        return null;
    }

    @Override
    public void updateDevice(DeviceDto deviceDto) {
        BatchUpdateDeviceNicknameRequest nicknameRequest = new BatchUpdateDeviceNicknameRequest();
        nicknameRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        BeanUtil.copyProperties(deviceDto, info);
        nicknameRequest.setDeviceNicknameInfo(new ArrayList<>(Arrays.asList(info)));

        BatchUpdateDeviceNicknameResponse batchUpdateDeviceNicknameResponse = null;
        try {
            batchUpdateDeviceNicknameResponse = client.batchUpdateDeviceNickname(nicknameRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (!batchUpdateDeviceNicknameResponse.getBody().success) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        try {
            deviceMapper.updateByPrimaryKeySelective(BeanUtil.toBean(deviceDto, Device.class));
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

    }

    @Override
    public void deleteDevice(DeviceDto deviceDto) {
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        BeanUtil.copyProperties(deviceDto, deleteDeviceRequest);
        deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse deleteDeviceResponse = null;
        try {
            deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (deleteDeviceResponse.getBody().success) {
            deviceMapper.deleteByIotId(deviceDto.getIotId());
        } else {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }


    }


    private DeviceVo queryHuaweiDeviceDetail(DeviceDto deviceDto) {
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(deviceDto.getIotId());
        request.withInstanceId(huaweiProperties.getInstanceId());
        ShowDeviceResponse response = huaweiClient.showDevice(request);
        DeviceVo device = deviceMapper.queryDeviceByIotId(deviceDto.getIotId());
        device.setDeviceName(response.getNodeId());
        device.setIotId(response.getDeviceId());
        device.setDeviceSecret(response.getAuthInfo().getSecret());
        device.setGmtActive(response.getActiveTime());
        device.setGmtCreate(response.getCreateTime());
        device.setGmtOnline(response.getConnectionStatusUpdateTime());
        switch (response.getStatus()) {
            case "INACTIVE":
                device.setStatus("UNACTIVE");
                break;
            case "FROZEN":
                device.setStatus("DISABLE");
                break;
            case "ABNORMAL":
                device.setStatus("OFFLINE");
                break;
            default:
                device.setStatus(response.getStatus());
        }


        return device;
    }
}